package io.gitee.kotle.android.utils

import android.annotation.SuppressLint
import android.content.Context
import android.net.*
import androidx.annotation.RequiresPermission
import androidx.annotation.WorkerThread
import io.gitee.kotle.android.BaseGlobalConst
import io.gitee.kotle.android.iAnnotation.NetworkStatus

/**
 *
 * 描述：监听网络情况
 *
 * 创建人：jiale.wei
 * 创建时间：2021/11/11 9:16 上午
 *
 */
/**
 * 监听网络
 *  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 *  <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
 */
@RequiresPermission("android.permission.ACCESS_NETWORK_STATE")
fun startNetWorkObServe(listener: NetworkStatusUtil.StatusListener) {
    if (!NetworkStatusUtil.listenerList.contains(listener)) {
        NetworkStatusUtil.listenerList.add(listener)
    }
    listener.onNetWorkChange(NetworkStatusUtil.getNetWorkStates())
}


/**
 *  移除网络监听
 *  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 *  <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
 *
 */
@RequiresPermission("android.permission.ACCESS_NETWORK_STATE")
fun stopNetWorkObServe(listener: NetworkStatusUtil.StatusListener) {
    NetworkStatusUtil.listenerList.remove(listener)
}

/**
 * ping域名
 * [times]ping的次数
 * [timeout]每次ping的超时时间
 */
@WorkerThread
fun pingDomain(domain: String?, times: Int = 3, timeout: Int = 30): Boolean {
    domain ?: return false
    return ignoreError {
        Runtime.getRuntime()
            .exec("ping -c $times -w $timeout $domain")
            .waitFor() == 0
    } ?: false
}

object NetworkStatusUtil : ConnectivityManager.NetworkCallback() {
    const val NET_STATUS_LOSS = 1
    const val NET_STATUS_WIFI = 2
    const val NET_STATUS_CELLULAR = 3
    const val NET_STATUS_UNKNOWN = 4

    internal val listenerList = mutableListOf<StatusListener>()

    private val netServer =
        (BaseGlobalConst.app.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager)


    private var lastNetStatus: Int? = null

    /**
     * 网络是否链接
     */
    private var netWorkConnect = true


    val isNetWorkConnect: Boolean
        get() {
            return netWorkConnect
        }

    /**
     * 网络是否可用
     */
    private var netWorkAvailable = true

    val isNetWorkAvailable: Boolean
        get() {
            return netWorkAvailable
        }

    init {
        netServer.requestNetwork(
            NetworkRequest.Builder()
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
//            .also {//android11 会报错，暂时不知道啥原因
//                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
//                    it.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
//                }
//            }
                .build(), this
        )
    }

    /**
     * 判断网络是否可以使用，不考虑其他情况，可用就行
     */
    val isNetworkConnectAndAvailable: Boolean
        @SuppressLint("MissingPermission")
        @RequiresPermission("android.permission.ACCESS_NETWORK_STATE")
        get() {
            return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
                val network = netServer.activeNetwork
                val info = netServer.getNetworkCapabilities(network)
                info != null && info.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
            } else {
                val info = netServer.activeNetworkInfo
                info != null && info.isAvailable
            }
        }

    /***
     * 当前链接是否wifi
     * null:没有网络链接
     * true:wifi
     * false:有链接但不是wifi
     * 注意：比如有其他连接（比如vpn连接），这里返回为false
     */
    val isWifi: Boolean?
        @SuppressLint("MissingPermission")
        @RequiresPermission("android.permission.ACCESS_NETWORK_STATE")
        get() = checkNetwork(NetworkCapabilities.TRANSPORT_WIFI, ConnectivityManager.TYPE_WIFI)

    /**
     * 是否为蜂窝网
     */
    val isCellular: Boolean?
        @SuppressLint("MissingPermission")
        @RequiresPermission("android.permission.ACCESS_NETWORK_STATE")
        get() = checkNetwork(
            NetworkCapabilities.TRANSPORT_CELLULAR,
            ConnectivityManager.TYPE_MOBILE
        )

    /***
     * 当前链接是否vpn连接
     * null:没有网络链接
     * true:VPN
     * false:没有连接vpn
     */
    val isVpn: Boolean?
        @SuppressLint("MissingPermission")
        @RequiresPermission("android.permission.ACCESS_NETWORK_STATE")
        get() = checkNetwork(NetworkCapabilities.TRANSPORT_VPN, ConnectivityManager.TYPE_VPN)

    /**
     * 是否使用代理上网
     */
    val isWifiProxy: Boolean
        get() {
            if (isWifi != true) {
                return false
            }
            val proxyAddress = System.getProperty("http.proxyHost")
            val portStr = System.getProperty("http.proxyPort")
            return !proxyAddress.isNullOrBlank() || !portStr.isNullOrBlank()
        }

    @SuppressLint("MissingPermission")
    @RequiresPermission("android.permission.ACCESS_NETWORK_STATE")
    private fun checkNetwork(transportType: Int, type: Int): Boolean? {
        if (!isNetWorkConnect) {
            return null
        }
        return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            val network = netServer.activeNetwork
            val info = netServer.getNetworkCapabilities(network)
            info != null && info.hasTransport(transportType)
        } else {
            val info = netServer.activeNetworkInfo
            info != null && info.isAvailable && info.type == type
        }
    }


    override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
        super.onCapabilitiesChanged(network, networkCapabilities)
        notifyListener()
    }

    override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
        super.onLinkPropertiesChanged(network, linkProperties)
        notifyListener()
    }

    override fun onLost(network: Network) {
        super.onLost(network)
        netWorkConnect = false
        notifyListener()
    }

    override fun onUnavailable() {
        super.onUnavailable()
        netWorkAvailable = false
        notifyListener()
    }

    override fun onLosing(network: Network, maxMsToLive: Int) {
        super.onLosing(network, maxMsToLive)
        notifyListener()
    }

    override fun onAvailable(network: Network) {
        super.onAvailable(network)//网络可用
        netWorkConnect = true
        netWorkAvailable = true
        notifyListener()
    }

    /**
     * 通知网络发生变化
     */

    @SuppressLint("MissingPermission")
    private fun notifyListener() {
        val currentStatus = getNetWorkStates()
        if (currentStatus == lastNetStatus) {
            return
        }
        lastNetStatus = currentStatus
        listenerList.forEach {
            it.onNetWorkChange(currentStatus)
        }
    }

    /**
     * 获取当前网络状态
     */
    @RequiresPermission("android.permission.ACCESS_NETWORK_STATE")
    @NetworkStatus
    fun getNetWorkStates(): Int {
        if (isNetWorkConnect) {
            if (isWifi == true) {
                return NET_STATUS_WIFI
            }
            if (isCellular == true) {
                return NET_STATUS_CELLULAR
            }
            return NET_STATUS_UNKNOWN
        } else {
            if (isNetworkConnectAndAvailable) {
                if (isWifi == true) {
                    return NET_STATUS_WIFI
                }
                if (isCellular == true) {
                    return NET_STATUS_CELLULAR
                }
                return NET_STATUS_UNKNOWN
            }
            return NET_STATUS_LOSS
        }
    }

    interface StatusListener {
        fun onNetWorkChange(@NetworkStatus status: Int)
    }
}